/**
 * @(#)Server.java
 *
 *
 * @author
 * @version 1.00 2012/3/26
 */

import java.net.ServerSocket;
import java.net.Socket;
import java.io.*;
import java.util.Scanner;

public class Server {

	private ServerSocket server;
	private Socket client;
	private PrintWriter toClient;
	private Scanner fromClient;
	private ConnectFourCore game;

    public Server(int port) {
    	server = null;
    	client = null;
    	toClient = null;
    	fromClient = null;
    	openListenPort(port);
    	acceptClientRequest();
    }

    public void setGame(ConnectFourCore game) { this.game = game; }
    public ConnectFourCore getGame() { return game; }

    public void openListenPort(int port)
    {
    	if(server.isBound()) {
    		System.err.println("The server is already listening to a port.");
    		return;
    	}
    	try { server = new ServerSocket(port); }
    	catch (IOException e) {
    		System.err.println("Could not listen on port: " + port);
    		System.exit(-1);
    	}
    }

    public void closeListenPort()
    {
    	if(server == null) {
    		System.err.println("No server socket exists.");
    		return;
    	}
    	if(!server.isClosed()) {
    		dropClient();
    		try { server.close(); }
	    	catch (IOException e) {
	    		System.err.println("Couldn't close the server connection.");
    			System.exit(1);
	    	}
    	}
    	server = null;
    }

    public boolean isConnected()
    {
    	return client.isConnected();
    }
    public void acceptClientRequest()
    {
    	if(client.isBound()) {
    		System.err.println("The server is already bound to a client.");
    		return;
    	}
    	if(server.isClosed()) {
    		System.err.println("The server must be open to connect.");
    		return;
    	}
    	if(!server.isBound()) {
    		System.err.println("The server must be listening first.");
    		return;
    	}
    	try {
    		client = server.accept();
    		toClient = new PrintWriter(client.getOutputStream(), true);
    		fromClient = new Scanner(client.getInputStream());
    	}
    	catch(IOException e) {
    		System.err.println("Accept failed.");
    		System.exit(1);
    	}
    }

    public void dropClient()
    {
    	if(client == null) {
    		System.err.println("No client to drop");
    		return;
    	}
    	if(!client.isClosed()) {
    		if(toClient != null) toClient.close();
	    	if(fromClient != null) fromClient.close();
	    	try { client.close(); }
	    	catch (IOException e) {
	    		System.err.println("Couldn't close the connection to the client.");
    			System.exit(1);
	    	}
    	}
    	toClient = null;
    	fromClient = null;
    	client = null;
    }

    public Boolean ackClientConnection() {
    	if(toClient == null) return false;
    	if(!client.isConnected()) return false;

    	toClient.println("WELCOME");
    	return true;
    }
    public Boolean sendClientGameInfo(int rows, int cols, int player, int time, char rules) {
    	if(toClient == null) return false;
    	if(!client.isConnected()) return false;

    	toClient.println("info " + rows + " " + cols + " " + player + " " + time + " " + rules);

    	//wait for ackServerGameInfo
    	if(fromClient.hasNextLine()&&fromClient.nextLine().trim().toUpperCase().equals("READY"))
    		return true;

    	return false;
    }
    public Boolean sendClientGameStart(){
    	if(toClient == null) return false;
    	if(!client.isConnected()) return false;

    	toClient.println("BEGIN");
    	return true;
    }
    public Boolean sendClientMove(char move, int col){
    	if(toClient == null) return false;
    	if(!client.isConnected()) return false;

    	toClient.println(move + ((col == 0) ? "" : (" " + col)));

		//wait for ackServerMove
    	if(fromClient.hasNextLine()&&fromClient.nextLine().trim().toUpperCase().equals("OK"))
    	{
    		processMove(move, col);
    		return true;
    	}

    	return false;
    }
    public Boolean ackClientMove()
    {
    	if(fromClient == null) return false;
    	if(!client.isConnected()) return false;

    	if(fromClient.hasNextLine())
    	{
    		String[] data = fromClient.nextLine().split(" ");
    		if(data.length != 0 && data.length < 3) {
    			processMove((data[0].toLowerCase().toCharArray()[0]),Integer.parseInt(data[1].toLowerCase()));
    		} else { return false; }
    	}

    	toClient.println("OK");
    	return true;
    }

    public Boolean sendClientTime()
    {
    	if(toClient == null) return false;
    	if(!client.isConnected()) return false;

    	toClient.println("TIME");
    	return true;
    }

    public Boolean sendClientResults()
    {
    	return true;
    }

	private Boolean processMove(char move, int col)
	{
		switch(move)
		{
			case 'd':
				game.Drop(col);
				return true;
			case 'r':
				game.Remove(col);
				return true;
			case 'f':
				game.Flip();
				return true;
		}
		return false;
	}
}